﻿<documents created="2010-12-15 11:38:06Z"><document src="C:\Users\Anders\Documents\automatones\Visual Studio\AutomaTones\AutomaTones\Controller\MainController.cs" renderPrefix="s0"><chunk hits="-1" domain="unknown"><source><![CDATA[/**
 * The Maincontroller knows all controllers in the system. Thus master volume, pause, 
 * play etc. can easily be controlled from here. Views can register themselves to the maincontroller
 * on when apropiate. The main controller choses what IController sub-type that will control a 
 * registring view.
 * Author: Anders Høst | ahkj@itu.dk
 * Date: 05 Dec 2010
 */

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading;
using AutomaTones.HW_Sense_Compute;
using AutomaTones.Model.MIDI;
using AutomaTones.Model.MIDI.Mappers;
using AutomaTones.View;
using AutomaTones.View.Launchpad_View;
using AutomaTones.View.Midi_Out_View;
using Microsoft.Pex.Framework;
using Midi;

namespace AutomaTones.Controller {
    [PexClass]
    public partial class MainController {
        private List<IController<IView>> _CAcontrollers = new List<IController<IView>>();
        private IController<IMasterView> _masterViewController;
        private List<Channel> _midiChannels = new List<Channel>();
        private IHardwareView _hardWareView;
        private ComputeLaunchpad _computeLaunchpad;
        public static bool LaunchpadConnected;
        public static Tempo Tempo;

        [PexMethod]
        public void Init() {
            // Global tempo used
            Tempo = new Tempo(110);
            AddChannels();
            
            // Try to make the connection to the Launchpad. Handles the exception if it's not present.
            try {
                SetupLaunchpad();
                LaunchpadConnected = true;
            }
            catch (Exception ex) {
                Console.WriteLine(ex.Message);
                LaunchpadConnected = false;
            }
            ThreadPool.QueueUserWorkItem(delegate { Run(); });
        }

        /// <summary>
        /// Add a view that implements the IVEW interface.
        /// </summary>
        /// <param name="view"></param>
        [PexMethod]
        public void AddIView(IView view) {
            Contract.Requires(view != null);
            Contract.Ensures(Contract.OldValue(_CAcontrollers.Count) < _CAcontrollers.Count);
            IController<IView> con = new CAViewController();

            con.Channels = MidiChannels;
            con.AddView(view);
            if(_hardWareView!=null)
              ((CAViewController)con).AddHwView(_hardWareView);

            con.SetUp();
            lock (_CAcontrollers)
            {
                ((List<IController<IView>>) _CAcontrollers).Add(con);
            }
            ConnectLaunchpadToControllers();
        }

        /// <summary>
        /// The heart beat of the system. Pulsates a base beat to all VaViewControllers.
        /// </summary>
        [PexMethod]
        private void Run() ]]></source>
</chunk>
<method name="Run" namespace="AutomaTones.Controller" type="AutomaTones.Controller.MainController" typeName="MainController" token="6000190" module="AutomaTones.exe"><hits><hit index="0" value="1"/>
<hit index="1" value="770"/>
<hit index="2" value="770"/>
<hit index="3" value="770"/>
<hit index="4" value="770"/>
<hit index="5" value="770"/>
<hit index="6" value="770"/>
<hit index="7" value="770"/>
<hit index="8" value="1540"/>
<hit index="21" value="770"/>
<hit index="22" value="769"/>
<hit index="23" value="769"/>
<hit index="30" value="769"/>
<hit index="31" value="769"/>
<hit index="32" value="769"/>
<hit index="33" value="769"/>
<hit index="36" value="769"/>
<hit index="37" value="769"/>
<hit index="38" value="769"/>
<hit index="39" value="769"/>
<hit index="40" value="1538"/>
<hit index="53" value="769"/>
<hit index="54" value="769"/>
<hit index="55" value="769"/>
<hit index="62" value="769"/>
<hit index="63" value="769"/>
<hit index="64" value="769"/>
<hit index="65" value="769"/>
<hit index="71" value="769"/>
<hit index="72" value="769"/>
<hit index="73" value="769"/>
<hit index="76" value="769"/>
<hit index="77" value="769"/>
<hit index="78" value="769"/>
<hit index="79" value="1538"/>
<hit index="80" value="769"/>
<hit index="81" value="769"/>
</hits>
<coverage domain="userortestcode" unit="block" covered="15" total="27" coveredRatio="0.55555555555555558"/>
</method>
<chunk hits="1" offset="0000" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
            ]]></source>
</chunk>
<chunk hits="770" offset="00eb" domain="userortestcode"><source><![CDATA[while (true)]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="770" offset="0006" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                ]]></source>
</chunk>
<chunk hits="770" offset="0009" domain="userortestcode"><source><![CDATA[lock (_CAcontrollers)]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="770" offset="0019" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                    ]]></source>
</chunk>
<chunk hits="770" offset="001a" domain="userortestcode"><source><![CDATA[foreach]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ (]]></source>
</chunk>
<chunk hits="0" offset="0029" domain="userortestcode"><source><![CDATA[CAViewController c]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="2310" offset="0050" domain="userortestcode"><source><![CDATA[in]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="770" offset="001b" domain="userortestcode"><source><![CDATA[_CAcontrollers]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[) ]]></source>
</chunk>
<chunk hits="0" offset="0036" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                        ]]></source>
</chunk>
<chunk hits="0" offset="0037" domain="userortestcode"><source><![CDATA[if (c.IsPLaying)]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="0" offset="0046" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                            ]]></source>
</chunk>
<chunk hits="0" offset="0047" domain="userortestcode"><source><![CDATA[c.Evolve();]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                        ]]></source>
</chunk>
<chunk hits="0" offset="004e" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                    ]]></source>
</chunk>
<chunk hits="0" offset="004f" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                    ]]></source>
</chunk>
<chunk hits="769" offset="006f" domain="userortestcode"><source><![CDATA[foreach]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ (]]></source>
</chunk>
<chunk hits="0" offset="007e" domain="userortestcode"><source><![CDATA[CAViewController c]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="2307" offset="00a5" domain="userortestcode"><source><![CDATA[in]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="769" offset="0070" domain="userortestcode"><source><![CDATA[_CAcontrollers]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[) ]]></source>
</chunk>
<chunk hits="0" offset="008b" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                        ]]></source>
</chunk>
<chunk hits="0" offset="008c" domain="userortestcode"><source><![CDATA[if (c.IsPLaying)]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[ ]]></source>
</chunk>
<chunk hits="0" offset="009b" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                            ]]></source>
</chunk>
<chunk hits="0" offset="009c" domain="userortestcode"><source><![CDATA[c.Play();]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                        ]]></source>
</chunk>
<chunk hits="0" offset="00a3" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                    ]]></source>
</chunk>
<chunk hits="0" offset="00a4" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                ]]></source>
</chunk>
<chunk hits="769" offset="00c4" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
                ]]></source>
</chunk>
<chunk hits="769" offset="00da" domain="userortestcode"><source><![CDATA[Thread.Sleep(Tempo.SixteenthNote());]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
            ]]></source>
</chunk>
<chunk hits="769" offset="00ea" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
        }

        /// <summary>
        /// Adding a masterview to a maincontroller will replace the existing masterview.
        /// </summary>
        /// <param name="?"></param>
       [PexMethod]
        public void AddMasterView(IMasterView imv) {
            this._masterViewController = (IController<IMasterView>)new MasterViewController(this);
            ((IController<IMasterView>)_masterViewController).AddView(imv);
            this._masterViewController.SetUp();
        }

        /// <summary>
        /// Property for Midichannels. The channels propogates from here to the rest of the controllers.
        /// </summary>
        public List<Channel> MidiChannels {
            get { return _midiChannels; }
            set { _midiChannels = value; }
        }

        [PexMethod]
        private void SetupLaunchpad() {              
            ConnectLaunchpad clp = new ConnectLaunchpad();
            SenseLaunchpad slp = new SenseLaunchpad();
            _computeLaunchpad = slp.ComputeLaunchpad;
            _hardWareView = new LaunchPad();
            ConnectLaunchpadToControllers();
            ((LaunchPad)_hardWareView).ClearGrid();
            slp.StartSensing();
            
        }

        private void ConnectLaunchpadToControllers() {
            foreach (CAViewController controller in _CAcontrollers)
            {
                if (LaunchpadConnected) {
                    _computeLaunchpad.LaunchpadEvent += controller.LaunchpadClicked;
                    _computeLaunchpad.StateButtonEvent += controller.StateButtonDown;
                    _computeLaunchpad.StateChangeEvent += controller.State;
                    _computeLaunchpad.OkButtonEvent += controller.Ok;
                    _computeLaunchpad.ClearButtonEvent += controller.ResetGrid;
                }
            }
        }

        /// <summary>
        /// Add channels to the system. Calling this method will make the 
        /// Maincontroller detect all available channels.
        /// </summary>
        private void AddChannels() {
            List<Channel> avalChannels = Enum.GetValues(typeof (Channel)).Cast<Channel>().ToList();
            _midiChannels = avalChannels;
        }

        /********************************************************************************
         * MasterViewController as an inner class so it can access the CaViewControllers
         ********************************************************************************/

       class MasterViewController : IController<IMasterView> {
           private IMasterView _view;
           private int _masterChannel = 16;
           private ConnectVirtualMidi _vm;
           private MidiOut _mo;
   
           public MasterViewController(MainController m) {
               this.MainController = m;
               _vm = new ConnectVirtualMidi();
               _mo = _mo = new MidiOut(Channel.Channel16, new BechTranslator());
           }
   
           /// <summary>
           /// Add the IMasterView to this controller.
           /// </summary>
           /// <param name="v"></param>
           public void AddView(IMasterView v) {
               Contract.Requires(v != null);
               Contract.Requires(this.MainController != null);
               Contract.Ensures(this._view == v);
               _view = v;
           }
           [PexMethod]
           public void SetUp() {
               _view.OnForwardButtonClickEvent += Forward;
               _view.OnPauseButtonClickEvent += Pause;
               _view.OnPlayButtonClickEvent += Play;
               _view.OnRewindButtonClickEvent += Rewind;
               _view.OnVolumeChangeEvent += VolumeChanged;
           }

           /// <summary>
           /// Send a Forward message to all CA
           /// </summary>
           [PexMethod]
           public void Forward() {
               lock (MainController._CAcontrollers){
                   foreach (CAViewController cac in MainController._CAcontrollers){
                       cac.Forward();
                   }
               }
           }
   
           /// <summary>
           /// Send pause message to all CA
           /// </summary>
           [PexMethod]
           public void Pause(){
               lock (MainController._CAcontrollers) {
                   foreach (CAViewController cac in MainController._CAcontrollers) {
                       cac.Pause();
                   }
               }
           }
   
           /// <summary>
           /// Send Play to all CA
           /// </summary>
           [PexMethod]       
           public void Play() {
               lock (MainController._CAcontrollers) {
                   foreach (CAViewController cac in MainController._CAcontrollers) {
                       cac.PlaySentFromUser();
                   }
               }
           }
   
           /// <summary>
           /// Send Rewind to all CA
           /// </summary>
           [PexMethod]
           public void Rewind() {
               lock (MainController._CAcontrollers) {
                   foreach (CAViewController cac in MainController._CAcontrollers) {
                       cac.Rewind();
                   }
               }
           }
   
           /// <summary>
           /// Turn down the volume. It directs the call directly to the midi out, thus not affecting the CA.
           /// </summary>
           /// <param name="volume"></param>
           [PexMethod]      
           public void VolumeChanged(int volume) {
                _mo.SetVolume(volume);
           }

           /// <summary>
           /// As is, evolve is omitted for this implementation, this might be useful for an some extende use of CA
           /// </summary>
           public void Evolve(){}

           private MainController MainController { get; set; }
   
           public bool IsPLaying { get; set; }
   
           public int Volume { get; set; }

           public List<Channel> Channels { get; set; }
           [ContractInvariantMethod]
           private void Invariant() {
               Contract.Invariant(0 <= Volume && Volume <= 100);
           }
       }
   }
}
]]></source>
</chunk>
</document>
<document src="C:\Users\Anders\Documents\automatones\Visual Studio\AutomaTones\AutomaTones\Model\MIDI\Tempo.cs" renderPrefix="s1"><chunk hits="-1" domain="unknown"><source><![CDATA[using System.Diagnostics.Contracts;
using Microsoft.Pex.Framework;

namespace AutomaTones.Model.MIDI
{
    /// <summary>
    /// Class the can translate a musical format of time (Beats Per Minute) to milliseconds used by Threads.
    /// Instanciate with a BPM and then call the methods to get the corrects value in milliseconds for the called subdivision.
    /// </summary>
    /// <author>Anders Bech Mellson, anbh@itu.dk</author>
    [PexClass]
    public class Tempo {
        private readonly int _bpm;

        /// <summary>
        /// Creates a tempo object with the desired tempo in Beats per minute.
        /// </summary>
        /// <param name="BPM"></param>
        public Tempo(int BPM) {
            Contract.Requires(BPM>0);
            this._bpm = BPM;
        }

        /// <summary>
        /// Return the current BPM.
        /// </summary>
        [PexMethod]
        public int BPM() {
            return _bpm;
        }

        /// <summary>
        /// Returns the value of a wholenote in milliseconds.
        /// </summary>
        [PexMethod]
        public int WholeNote() {
            return 240000/_bpm;
        }

        /// <summary>
        /// Returns the value of a halfnote in milliseconds.
        /// </summary>
        [PexMethod]
        public int HalfNote() {
            return 120000/_bpm;
        }

        /// <summary>
        /// Returns the value of a quarternote in milliseconds.
        /// </summary>
        [PexMethod]
        public int QuarterNote() {
            return 60000/_bpm;
        }

        /// <summary>
        /// Returns the value of a eightnote in milliseconds.
        /// </summary>
        [PexMethod]
        public int EighthNote() {
            return 30000/_bpm;
        }

        /// <summary>
        /// Returns the value of a sixteenthnote in milliseconds.
        /// </summary>
        [PexMethod]
        public int SixteenthNote() ]]></source>
</chunk>
<method name="SixteenthNote" namespace="AutomaTones.Model.MIDI" type="AutomaTones.Model.MIDI.Tempo" typeName="Tempo" token="600018c" module="AutomaTones.exe"><hits><hit index="0" value="769"/>
<hit index="1" value="769"/>
<hit index="2" value="769"/>
<hit index="3" value="769"/>
</hits>
<coverage domain="userortestcode" unit="block" covered="1" total="1" coveredRatio="1"/>
</method>
<chunk hits="769" offset="0000" domain="userortestcode"><source><![CDATA[{]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
            ]]></source>
</chunk>
<chunk hits="769" offset="0001" domain="userortestcode"><source><![CDATA[return 15000/_bpm;]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[
        ]]></source>
</chunk>
<chunk hits="1538" offset="0010" domain="userortestcode"><source><![CDATA[}]]></source>
</chunk>
<chunk hits="-1" domain="unknown"><source><![CDATA[

        /// <summary>
        /// Returns the value of a thirtysecondnote in milliseconds.
        /// </summary>
        [PexMethod]
        public int ThirtySecondNote() {
            return 7500/_bpm;
        }
    }
}
]]></source>
</chunk>
</document>
</documents>
